Imports System.IO.IsolatedStorage
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Runa
Imports Runa.Common.Helper
Imports Runa.Core.GamePackage
Imports Runa.Core.Services
Imports Runa.Foundation
Imports Runa.Foundation.Diagnostics
Imports Runa.Foundation.Messaging
Imports Runa.Foundation.Runtime
Imports Runa.Foundation.Runtime.Serialization
Imports Runa.Foundation.Threading
Imports Runa.Resources.ContentManagers
Imports Runa.Resources.ResourceManager
Imports Runa.Scripting.ScriptingHost
Imports Runa.UI.Input

#If Not NETFX_CORE Then
Imports System.Windows.Forms
#Else
#End If

''' <summary>
''' This is the main type for your game
''' </summary>
Partial Public Class GameRender
    Inherits Microsoft.Xna.Framework.Game

    Public Event Shown(ByVal sender As Object, ByVal e As EventArgs)

    Public WithEvents SystemSpriteBatch As SpriteBatch

    Public Sub New()
        Me.m_graphics = New GraphicsDeviceManager(Me)
        Me.m_graphics.PreferMultiSampling = True
        If GameRender.GamePackage Is Nothing Then Throw New ArgumentException("Null game package.")
        With GameRender.GamePackage
            Me.m_physicalStorage = .PhysicalStorage
            Me.Name = .Name
            Me.Author = .Author
            Me.Fps = .Fps
            Me.GPUAccelerationEnabled = .GPUAccelerationEnabled
#If (Not NETFX_CORE) And (Not WINDOWS_PHONE) Then
            Me.WindowHeight = .WindowHeight
            Me.WindowWidth = .WindowWidth
            Me.m_graphics.IsFullScreen = .IsFullScreen
            Me.Icon = .Image
#End If
            Me.GameContentRoot = .GameContentRoot
        End With
    End Sub

    ''' <summary>
    ''' Import information from the package extractor.
    ''' </summary>
    ''' <param name="pkgExtractor"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pkgExtractor As GamePackageBase)
        Me.m_graphics = New GraphicsDeviceManager(Me)
        Me.m_graphics.PreferMultiSampling = True
        GameRender.GamePackage = pkgExtractor
        With pkgExtractor
            Me.m_physicalStorage = .PhysicalStorage
            Me.Name = .Name
            Me.Author = .Author
            Me.Fps = .Fps
            Me.GPUAccelerationEnabled = .GPUAccelerationEnabled
#If (Not NETFX_CORE) And (Not WINDOWS_PHONE) Then
            Me.WindowHeight = .WindowHeight
            Me.WindowWidth = .WindowWidth
            Me.m_graphics.IsFullScreen = .IsFullScreen
            Me.Icon = .Image
#End If
            Me.GameContentRoot = .GameContentRoot
        End With
    End Sub

    Protected Overrides Sub Initialize()
        Dim asm = Me.GetType().Assembly

        Dim oldResolution As New Vector2
        With Me
            Me.m_graphics.TryChangeResolution(New Vector2(.WindowWidth, .WindowHeight), oldResolution)
        End With

        Me.Services.AddService(GetType(IGameParameterService), Me)
        Me.Services.AddService(GetType(ISafeNativeMethods), Me)

        Me.m_resourceStreamContentManager = New ResourceStreamContentManager(Me.Content.ServiceProvider, asm.GetName().Name.Replace(" ", "_"), asm)
        Me.m_contentManager = New GameDirectoryContentManager(Me.Game.Content.ServiceProvider, Me.GameContentRoot, Me.m_physicalStorage)
        Me.GameTracer = Tracer.Add(Me.Name, Path.Combine(Me.m_contentManager.RootDirectory, Me.Name))

#If WINDOWS Then
        Me.Content.RootDirectory = "Content"
        Me.NativeContent = Me.Content
#End If

        Me.Content = Me.m_contentManager

        Me.RegisterWindowClass(Me)

        Call BindingInputDeviceEvent()

        ' Initialize the ScriptTask object for GameLoop class.
        Dim gameLoopScriptTask = New ScriptTask("GameLoop.rb")
        Me.ScriptObjects.Add("GameLoop", gameLoopScriptTask)
        Me.BindingScriptTaskOnErrorEvent()
        Me.BindingScriptTaskOnOnCompilationFailedEvent()
        gameLoopScriptTask.LoadScriptFromGameDirectory(Path.Combine(Me.m_contentManager.RootDirectory, "GameLoop.rb"), Me.m_physicalStorage)

        Call AddBasicReference(gameLoopScriptTask)
        gameLoopScriptTask.Execute(
            "gl = GameLoop.new(MyGame)" & vbCrLf & _
            "gl", _
            New System.MutableTuple(Of String, Object)("MyGame", Me))
        Me.BasicGameLoop = CType(gameLoopScriptTask.Result, BasicGameLoopGameComponent)

        Try
            Me.BasicGameLoop.Initialize()
            MyBase.Initialize()
        Catch ex As Exception
            Debuger.TraceListener.WriteLine(ex.Message & ex.StackTrace.ToString())
        End Try
    End Sub

    Protected Overrides Sub LoadContent()
        Me.SystemSpriteBatch = New SpriteBatch(GraphicsDevice)

        Try
            Me.LastScreenShot = New RenderTarget2D(GraphicsDevice, Me.WindowWidth, Me.WindowHeight, False, SurfaceFormat.Color, Nothing)
        Catch ex As Exception
            Me.LastScreenShot = New RenderTarget2D(GraphicsDevice, Me.WindowWidth, Me.WindowHeight)
        End Try

        Me.m_splashTexture = New Texture2DObject("SplashScreen", "SplashScreen.xnb", Me.m_resourceStreamContentManager.Load(Of Texture2D)("SplashScreen.xnb"))
        Dim center As New Vector2(Me.WindowWidth \ 2, Me.WindowHeight \ 2)
        Me.m_splashTexturePos = center - Me.m_splashTexture.GetAnchorPoint(AnchorPoint.Center)

        If Me.m_contentManager.PhysicalStorage.FileExists(Me.SaveDataFileName) Then
            Using fs = Me.m_contentManager.PhysicalStorage.OpenFile(Me.SaveDataFileName, Foundation.IO.FileMode.Open)
                Try
                    Me.GlobalStatus = Me.m_Serializer.Deserialize(Of Dictionary(Of String, Object))(fs)
                Catch ex As Exception
                    Exit Try
                End Try
            End Using
        End If

        Try
#If DEBUG Then
            Me.m_gameLoaded = False
            Me.BasicGameLoop.LoadContent()
            MyBase.LoadContent()
            Me.m_gameLoaded = True
            RaiseEvent Shown(Me, New EventArgs())
#Else
#If (Not NETFX_CORE) And (Not ASYNC_LOAD) Then
            Dim thr As New System.Threading.Tasks.Task(
                Sub()
#End If
            Me.m_gameLoaded = False

            Me.BasicGameLoop.LoadContent()

            MyBase.LoadContent()

            Me.m_gameLoaded = True

            RaiseEvent Shown(Me, New EventArgs())
#If (Not NETFX_CORE) And (Not ASYNC_LOAD) Then
                End Sub)
            thr.Start()
#End If
#End If
        Catch ex As Exception
            Debuger.TraceListener.WriteLine(ex.Message & ex.StackTrace.ToString())
        End Try
    End Sub

    Protected Overrides Sub UnloadContent()
        Me.GlobalSave()
        MyBase.UnloadContent()
    End Sub

    Protected Overrides Sub Update(gameTime As Microsoft.Xna.Framework.GameTime)
        Try
            ' TODO: Add your update logic here
            If Me.m_gameLoaded = True Then
                Dim gt As New GameTimeEventArgs(gameTime)

                Dim msg As Runa.Foundation.Messaging.Message = Nothing
                If Me.PeekMessage(msg, Thread.CurrentThread.ThreadID, True) Then
                    Me.WndProc(msg)
                End If

                Me.UpdateTimers(gt)
                Me.BasicGameLoop.Update(gt)
            End If
        Catch ex As Exception
            Debuger.TraceListener.WriteLine(ex.Message & ex.StackTrace.ToString())
        End Try
        MyBase.Update(gameTime)
    End Sub

    Private Sub OnDraw(ByVal gameTime As GameTime)
        Try
            If Me.m_gameLoaded = True Then
                Dim gt As New GameTimeEventArgs(gameTime)
                Me.BasicGameLoop.Draw(gt)
                MyBase.Draw(gameTime)
            Else
                If Me.m_splashTexture IsNot Nothing Then
                    MyBase.GraphicsDevice.Clear(New Color(200, 200, 200))
                    Me.SystemSpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend)
                    Me.SystemSpriteBatch.Draw(Me.m_splashTexture.Texture, Me.m_splashTexturePos, Color.White)
                    Me.SystemSpriteBatch.End()
                    MyBase.Draw(gameTime)
                End If
            End If
        Catch ex As Exception
            Debuger.TraceListener.WriteLine(ex.Message & ex.StackTrace.ToString())
        End Try    
    End Sub

    Protected Overrides Sub Draw(gameTime As Microsoft.Xna.Framework.GameTime)
        ' TODO: Add your drawing code here
        If Me.m_screenShotGotton = True Then
            SyncLock Me.LastScreenShot
                Me.GraphicsDevice.SetRenderTarget(Me.LastScreenShot)
                Call Me.OnDraw(gameTime)
                Me.EndTakeScreenShot()
            End SyncLock
        Else
            MyBase.GraphicsDevice.Clear(Color.Black)
            Call Me.OnDraw(gameTime)
        End If
    End Sub

    Private Sub OnInputDataArrived(sender As Object, e As InputEventArgs)
        Try
            If Me.m_gameLoaded = True Then
                Dim msg = Runa.Foundation.Messaging.Message.Create(Nothing, e.Message, e.ChangedProperty, CType(sender, InputHandler))
                ' Me.SendMessage(msg)
                msg.HWnd = New Object()
                Me.TranslateMessage(msg)
                Me.DispachMessage(msg)
            End If
        Catch ex As Exception
            Debuger.TraceListener.WriteLine(ex.Message & ex.StackTrace.ToString())
            Exit Sub
        End Try
    End Sub

#If WINDOWS Then

    Private Sub GameRender_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
        Dim msg = String.Format("Game is being disposed at {0}...", DateTime.Now.ToString())
        'MessageBox.Show(msg)
        Tracer.Default.TraceMessage(msg)
        'Environment.FailFast("Exit clearly.")
        'TerminateProcess(Process.GetCurrentProcess().Handle, 1)
        Process.GetCurrentProcess().Kill()
    End Sub

    Private Sub GameRender_Exiting(sender As Object, e As EventArgs) Handles Me.Exiting
        Dim msg = String.Format("Game is exiting at {0}...", DateTime.Now.ToString())
        'MessageBox.Show(msg)
        Tracer.Default.TraceMessage(msg)
    End Sub

#End If

End Class